<template>
  <div class="cesium-wrap" :class="sceneStore.mouseClass">
    <div id="cesiumContainer"></div>
    <div class="distance-label" v-if="distanceLabel">
      <div class="distance-label-line" :style="{ width: distanceWidth }">{{ distanceLabel }}</div>
    </div>
    <div class="tool-box" :class="toolBoxClass">
      <div class="tool-item" v-for="list in toolList" :key="list.code" @click="toolChange(list)">
        <SvgIcon
          :style="{ transform: `rotate(${list.code === 1 ? -northAngle : 0}deg)` }"
          :icon-class="list.icon"
        >
        </SvgIcon>
      </div>
    </div>
    <div class="lonlat" :class="lonlatClass">
      高度：{{ lonlat.height }} 经度：{{ lonlat.longitude }} 纬度：{{ lonlat.latitude }}
    </div>
    <!-- 白模编辑确认 -->
    <div
      class="whitemodel-delete-wrap"
      :style="{ left: whiteModelPosition.x + 'px', top: whiteModelPosition.y + 'px' }"
    >
      <div class="title-wrap">
        <SvgIcon icon-class="warn"> </SvgIcon>
        <div class="title">是否删除白模?</div>
      </div>
      <div class="btn-wrap">
        <div class="btn btn-cancel" @click="mapClick">取消</div>
        <div class="btn btn-delete" @click="deleteWhiteModel">删除</div>
      </div>
    </div>
  </div>
  <!-- 加载进度条 -->
  <Loading
    v-if="isShowLoading"
    :loading-complete="loadingComplete"
    @close="isShowLoading = false"
  />
</template>

<script setup lang="ts">
import { useRoute } from 'vue-router';
import { verifyResource } from '@/api/scene';
import {
  addLayer,
  addPanelTag,
  addSceneEvent,
  createLayerClickCallbackEvent,
  getLayerMap,
  importModelCallBack,
  setLayerVisible,
} from '@/service';
import { addlayerRequestIns } from '@/service/effect';
import { useSceneStore } from '@/store/scene';
import {
  createTreeFromFlatArray,
  flattenTreeIterative,
  judgeIsDevelop,
  randomString,
  retFilePath,
  sortTreeData,
} from '@/utils';
import { cloneDeep, round } from 'lodash';
import Loading from './loading.vue';

defineOptions({
  name: 'Cesium',
});

const route = useRoute();
const sceneStore = useSceneStore();
const isShowLoading = ref<boolean>(true);
const loadingComplete = ref<boolean>(false);
// 比例尺
const distanceLabel = ref<string>('');
const distanceWidth = ref<string>('100%');
// 经纬度
const lonlat = ref<any>({
  longitude: 0,
  latitude: 0,
  height: 0,
});
// 指北角度
const northAngle = ref<number>(0);
// 白模确认框位置
const whiteModelPosition = ref<any>({ x: -1000, y: -1000 });
let whiteModelId: any = null;

const toolList = [
  { code: 1, name: '指北针', icon: 'ic_指南针' },
  { code: 2, name: '放大', icon: 'ic_+' },
  { code: 3, name: '缩小', icon: 'ic_-' },
  { code: 4, name: '全屏', icon: 'ic_全屏' },
  { code: 5, name: '默认视角', icon: 'ic_地球' },
];
const isFullScreen = ref<boolean>(false);
const dataSourceUrl = judgeIsDevelop() ? '/cimup/images/globe.png' : '/images/globe.png';

const defaultMapObject = {
  view: {
    longitude: 113.92878028208328,
    latitude: 30.089004097298577,
    height: 10000371.007221604,
    duration: 3,
    heading: 6.2831853071795765,
    pitch: -1.570782970133429,
    maxDistance: 10000000,
    initViewStatically: true,
  },
  materialMap: {
    dataSourceUrl: retFilePath('comm/public/config/MMT.json'),
  },
  light: {
    shadows: true,
    size: 4096,
    softShadows: true,
  },
  layers: [
    {
      enable: true,
      index: 0,
      type: 'base',
      mapType: 'SINGLEIMAGE',
      dataSourceUrl: dataSourceUrl,
      extent: [-180, -90, 180, 90],
    },
    {
      enable: true,
      index: 500,
      type: 'divTool',
    },
  ],
  postProcess: [
    {
      name: 'fxaa',
      enabled: true,
    },
  ],
};

const toolBoxClass = computed(() => {
  if (sceneStore.rightPanelVisible || sceneStore.mapPanelVisible) {
    return 'left';
  }
  return '';
});

const lonlatClass = computed(() => {
  if (sceneStore.rightPanelVisible || sceneStore.mapPanelVisible) {
    return 'left';
  }
  return '';
});

const init = async () => {
  const { CIMUP, Cesium } = window;

  const cimInstance = CIMUP.CimEngine.instance;

  window.cimInstance = cimInstance;
  if (!sceneStore.sceneDetail) return;
  let configJson = sceneStore.sceneDetail.configJson
    ? JSON.parse(sceneStore.sceneDetail.configJson)
    : null;
  if (configJson) {
    // 处理预置场景

    if (!configJson.cimup) {
      configJson = setDefaultSceneConfig(configJson);
    }

    // 粒子特效处理、参数化特效处理
    if (configJson.cimup.mapObject.entities) {
      for (const list of configJson.layer) {
        if (['entity', 'fake_particleSystem'].includes(list.type)) {
          const actualJson = configJson.cimup.mapObject.entities.filter(
            (item: any) => item.name === list.layerName
          );
          if (actualJson.length) {
            list.json = actualJson[0];
          }
        }
      }
    }
    // 初始化维护已存在字典--开始
    const layerMap = getLayerMap();
    configJson.layer.forEach((item: API.Scene.ILayer) => {
      // if (['imageLayer', 'osgb', '_3dtiles'].includes(item.type)) {
      //   item.attr = { position: [], rotation: [], ...item.json };
      // }
      if (item.type !== 'folder') {
        layerMap.set(item.code, item.code);
      }
    });
    sceneStore.layerList = configJson.layer.filter((v: any) => v.type !== 'folder');
    // 初始化维护已存在字典--结束

    // sceneStore.layerTree = configJson.layerTree || [];
    const data = cloneDeep(configJson.layer);
    const resourceIds = sceneStore.layerList
      .filter((v: any) => v.resourceId)
      .map((v: any) => v.resourceId);
    // 注意 此处在分享预览页面无需处理
    if (route.path.indexOf('/share/scene') === -1 && resourceIds.length > 0) {
      const fData = new FormData();
      fData.set('resoIds', resourceIds.join(','));
      // 获取图层文件夹已经被删除的资源
      const resIds = await verifyResource({
        data: fData,
      });
      // 更新layers 里面资源状态是否被删除
      updateStatus(data, resIds);
    }
    sceneStore.layerTree = createTreeFromFlatArray(data, {
      parentId: 'fe_parentId',
      id: 'fe_id',
    });
    sortTreeData(sceneStore.layerTree);

    // 白模处理
    const whiteModelList = configJson.layer.filter(
      (item: API.Scene.ILayer) => item.type === 'building'
    );
    if (!whiteModelList.length) {
      configJson.cimup.mapObject.layers
        .filter((item: any) => item.name === 'white_model')
        .forEach((item: any) => {
          configJson.layer.unshift({
            code: Math.random().toString().split('.')[1],
            show: true,
            json: null,
            name: '白模',
            layerName: item.name,
            desc: '',
            type: 'building',
          });
        });
    }

    // 底图
    sceneStore.onlineMapSels = configJson.layer
      .filter((item: API.Scene.ILayer) => item.type === 'imageLayer')
      .map((item: API.Scene.ILayer) => item.json.name);
    // 地形
    sceneStore.activeTerrains = configJson.layer
      .filter((item: API.Scene.ILayer) => item.name === 'Cesium地形')
      .map((item: API.Scene.ILayer) => item.json.name);
    // 白模
    sceneStore.activeWhiteMolds = configJson.layer
      .filter((item: API.Scene.ILayer) => item.json?.extra?.type === 'whiteMold')
      .map((item: API.Scene.ILayer) => item.json.name);

    configJson.cimup.mapObject.layers.forEach((item: any) => {
      if (item.type === 'base') {
        item.dataSourceUrl = dataSourceUrl;
      }

      if (item.type === 'gltfmodel' && item.createType) {
        // gltf模型处理
        item.readyCall = importModelCallBack;
      } else if (item.type === 'drawlabel') {
        // drawlabel处理
        item.drawCall = function (e: any) {
          const properties = e.properties;

          properties.name = 'poi_' + properties.id;
          return properties;
        };
      }
    });

    configJson = disposeEffect(configJson);
  }

  const cimInitParam: any = {
    config: {
      gisContainer: 'cesiumContainer',
      map: '谷歌',
      mapObject: configJson ? configJson.cimup.mapObject : defaultMapObject,
    },
  };
  if (configJson && configJson.cimup.options) {
    cimInitParam.config.options = configJson.cimup.options;
  }
  if (sceneStore.sceneDetail.longitude && sceneStore.sceneDetail.latitude) {
    if (cimInitParam.config.mapObject.position) {
      cimInitParam.config.mapObject.position.targetPosition = [
        Number(sceneStore.sceneDetail.longitude),
        Number(sceneStore.sceneDetail.latitude),
      ];
    } else {
      cimInitParam.config.mapObject.position = {
        targetPosition: [
          Number(sceneStore.sceneDetail.longitude),
          Number(sceneStore.sceneDetail.latitude),
        ],
      };
    }
  }
  cimInstance.init(cimInitParam);
  cimInstance.eventApi.addEventListener('set_data_complete', async () => {
    console.log('底座初始化结束');
    sceneStore.isCimupComplete = true;
    // div、entity、参数化 类型处理
    console.log('----layerList-----', sceneStore.layerList);
    sceneStore.layerList.forEach((item: API.Scene.ILayer) => {
      if (item.type === 'div') {
        addPanelTag({
          longitude: item.attr.position[0],
          latitude: item.attr.position[1],
          height: item.attr.position[2],
          ...item,
        });
        addlayerRequestIns(item);
      } else if (['entity', 'fake_particleSystem'].includes(item.type)) {
        addLayer(item);
      }
      createLayerClickCallbackEvent(item);
    });
    // 白模编辑
    cimInstance.api.addLayerEventListener('white_model', 'mouse_rightclick', function (e: any) {
      const id = e.clickObject?.id;
      const name = e.clickObject.name;
      if (sceneStore.preview) {
        return;
      }
      whiteModelPosition.value.x = e.position.x;
      whiteModelPosition.value.y = e.position.y;
      // 高亮描边
      cimInstance.api.highlightGraphicByName('white_model', name);
      whiteModelId = id;
    });
  });
  cimInstance.eventApi.addEventListener('camera_change', function () {
    const scaleObj = cimInstance.api.getSceneScale();
    if (scaleObj) {
      distanceLabel.value = scaleObj.distanceLabel;
      distanceWidth.value = scaleObj.barWidth + 'px';
    }
    // console.log('比例尺----', scaleObj);
    const cameraParam = cimInstance.api.getCameraParameter();
    // console.log(cameraParam);
    lonlat.value.longitude = round(cameraParam.longitude, 4);
    lonlat.value.latitude = round(cameraParam.latitude, 4);
    lonlat.value.height = round(cameraParam.height, 4);
    sceneStore.mapCameraHeight = round(cameraParam.height, 4);
    northAngle.value = cameraParam.heading * Cesium.Math.DEGREES_PER_RADIAN;
    // console.log('指北针---', cameraParam.heading * Cesium.Math.DEGREES_PER_RADIAN);
  });
  cimInstance.eventApi.addEventListener('scene_tile_loaded', tileLoadComplete);
};

function updateStatus(data: any[], deletedResIds: any[]) {
  data
    .filter((v: any) => v.type !== 'folder')
    .forEach((res: any) => {
      if (deletedResIds.includes(res.resourceId)) {
        res.fe_deleted = true;
      }
    });
}

function setDefaultSceneConfig(configJson: any) {
  configJson = {
    cimup: configJson,
    layer: [],
  };
  let isExistDivTool = false;
  let isExistBaseMap = false;
  for (const layer of configJson.cimup.mapObject.layers) {
    if (layer.type === 'base' && layer.mapType === 'SINGLEIMAGE') {
      // layer.dataSourceUrl = withBase() + '/images/globe.png';
      isExistBaseMap = true;
    } else if (layer.type === 'image') {
      configJson.layer.push({
        code: Math.random().toString().split('.')[1],
        show: true,
        json: layer,
        name: layer.name,
        layerName: layer.name,
        desc: '',
        type: 'imageLayer',
      });
    } else if (layer.type === 'gltfmodel') {
      const gltfmodelJson: API.Scene.ILayer = {
        code: Math.random().toString().split('.')[1],
        show: true,
        json: layer,
        name: layer.name,
        layerName: layer.name,
        desc: '',
        type: 'gltfmodel',
        attr: {
          position: layer.positions[0],
          translation: [0, 0, 0],
          rotation: layer.rotation,
          scale: layer.scale,
          color: '',
        },
      };
      if (!layer.createType) {
        gltfmodelJson.actualType = 'gltfmodeleffect';
      }
      configJson.layer.push(gltfmodelJson);
    } else if (layer.type === 'divTool') {
      isExistDivTool = true;
    }
  }
  if (!isExistBaseMap) {
    configJson.cimup.mapObject.layers.push({
      enable: true,
      index: 0,
      type: 'base',
      mapType: 'SINGLEIMAGE',
      dataSourceUrl: dataSourceUrl,
      extent: [-180, -90, 180, 90],
    });
  }
  if (!isExistDivTool) {
    configJson.cimup.mapObject.layers.push({
      enable: true,
      index: 500,
      type: 'divTool',
    });
  }

  return configJson;
}

function toolChange(item: any) {
  const { cimInstance } = window;
  if (item.code === 1) {
    cimInstance.api.setCameraHeadNorth();
    return;
  }
  if (item.code === 2) {
    cimInstance.api.forwardCameraByScale(0.1);
    return;
  }
  if (item.code === 3) {
    cimInstance.api.forwardCameraByScale(-0.1);
    return;
  }
  if (item.code === 4) {
    isFullScreen.value = !isFullScreen.value;
    if (isFullScreen.value) {
      cimInstance.api.fullScreen(document.body);
    } else {
      cimInstance.api.exitFullscreen();
    }
    return;
  }
  if (item.code === 5) {
    cimInstance.api.flyToHome();
  }
}

function disposeEffect(configJson: any) {
  const allGltfModelName: string[] = [];
  configJson.cimup.mapObject.layers.forEach((item: any) => {
    if (item.type === 'gltfmodel') {
      allGltfModelName.push(item.name);
    }
  });
  // 对于依赖模型的特效去除
  for (let i = configJson.cimup.mapObject.layers.length - 1; i >= 0; i--) {
    if (
      configJson.cimup.mapObject.layers[i].type === 'cim_particleSystem' &&
      allGltfModelName.includes(configJson.cimup.mapObject.layers[i].owner)
    ) {
      configJson.cimup.mapObject.layers.splice(i, 1);
      continue;
    }
  }
  return configJson;
}

onMounted(() => {
  init();
  (document.getElementById('cesiumContainer') as any).addEventListener('click', mapClick);
});

onBeforeUnmount(() => {
  (document.getElementById('cesiumContainer') as any).removeEventListener('click', mapClick);
});

function mapClick() {
  whiteModelPosition.value.x = -1000;
  whiteModelPosition.value.y = -1000;
  whiteModelId = null;
}

function deleteWhiteModel() {
  const { cimInstance } = window;
  if (!whiteModelId) return;
  cimInstance.api.removeLayerGraphicById('white_model', whiteModelId);
  mapClick();
}

function tileLoadComplete() {
  console.log('--地图加载完成--');
  loadingComplete.value = true;
}

watch(
  () => sceneStore.layerList,
  () => {
    const layerMap = getLayerMap();
    initTreeData();
    for (const list of sceneStore.layerList) {
      if (layerMap.get(list.code)) {
        setLayerVisible(list);
      } else {
        addLayer(list);
        createLayerClickCallbackEvent(list);
        layerMap.set(list.code, list.code);
      }
    }
  },
  {
    deep: true,
  }
);

watch(
  () => loadingComplete.value,
  () => {
    const { cimInstance } = window;
    if (loadingComplete.value) {
      cimInstance.eventApi.removeEventListener('scene_tile_loaded', tileLoadComplete);
      addSceneEvent();
    }
  }
);

function initTreeData() {
  const types = ['gltfmodel', 'tileset', 'point', 'polyline', 'polygon', 'bimModel'];
  const layerTree = cloneDeep(sceneStore.layerTree || []);
  const layerCodes = flattenTreeIterative(layerTree)
    .filter((v: any) => v.type !== 'folder')
    .map((v: any) => v.code);
  sceneStore.layerList.forEach((ele: any) => {
    // 处理在线地图是勾选，删除图层数据
    if (!layerCodes.includes(ele.code)) {
      const param = {
        ...ele,
        id: '',
        fe_id: randomString(),
        fe_checked: true,
        fe_indeterminate: false,
        fe_parentId: '',
      };
      param.id = param.fe_id;
      // 是否选中节点
      if (sceneStore.selectedLayerNode) {
        let updatedNodeData;
        // 文件夹
        if (sceneStore.selectedLayerNode.data.type === 'folder') {
          updatedNodeData = sceneStore.selectedLayerNode.data;
          param.fe_parentId = updatedNodeData.fe_id;
          updatedNodeData.children
            ? updatedNodeData.children.unshift(param)
            : (updatedNodeData.children = [param]);
        } else {
          const parent = sceneStore.selectedLayerNode.parent || { level: 0, data: [] };
          const currData = sceneStore.selectedLayerNode.data;
          if (parent.level === 0) {
            updatedNodeData = parent.data;
            const index = updatedNodeData.findIndex((item: any) => item.fe_id === currData.fe_id);
            updatedNodeData.splice(index, 0, param);
          } else {
            updatedNodeData = parent.data;
            param.fe_parentId = updatedNodeData.fe_id;
            const index = updatedNodeData.children.findIndex(
              (item: any) => item.fe_id === currData.fe_id
            );
            updatedNodeData.children.splice(index, 0, param);
          }
        }
      } else {
        sceneStore.layerTree.unshift(param);
        console.log(param, sceneStore.layerTree);
      }
    }
  });
}
</script>

<style lang="less" scoped>
.cesium-wrap,
#cesiumContainer {
  position: absolute;
  width: 100%;
  height: 100%;

  &.select {
    cursor: url('~@/assets/png/ic_吸管.png') 0 0, auto;
  }

  &.selectable {
    cursor: url('~@/assets/png/ic_可选择状态.png') 0 0, auto;
  }

  &.unselectable {
    cursor: url('~@/assets/png/ic_不可选.png') 0 0, auto;
  }
}
.cesium-wrap {
  position: relative;
  overflow: hidden;
  .distance-label {
    position: absolute;
    right: 20px;
    bottom: 50px;
    display: flex;
    justify-content: center;
    align-items: flex-end;
    height: 36px;
    background: #303640;
    border-radius: 8px;
    color: #fff;
    font-size: 14px;
    padding: 7px 20px;
    &-line {
      display: flex;
      justify-content: center;
      align-items: flex-end;
      width: 100%;
      height: 8px;
      border: 1px solid #ffffff;
      border-top: none;
      line-height: 22px;
    }
  }
  .tool-box {
    position: absolute;
    top: 98px;
    right: 20px;
    transition: right 0.4s ease-out;
    .tool-item {
      display: flex;
      justify-content: center;
      align-items: center;
      width: 36px;
      height: 36px;
      background: #2a2e33;
      border-radius: 4px;
      margin-bottom: 10px;
      cursor: pointer;
      .svg-icon {
        margin-right: 0px;
        font-size: 24px;
      }
    }

    &.left {
      right: 356px;
    }
  }
  .lonlat {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 30px;
    background: #222528;
    color: #e8e8e8;
    font-size: 14px;
    padding: 0 20px;
    border-top: 1px solid #000;

    &.left {
      padding-right: 355px !important;
    }
  }
  .whitemodel-delete-wrap {
    position: absolute;
    width: 186px;
    height: 108px;
    background: #161616;
    box-shadow: 0px 12px 48px 16px rgba(0, 0, 0, 0.03), 0px 9px 28px 0px rgba(0, 0, 0, 0.05),
      0px 6px 16px -8px rgba(0, 0, 0, 0.08);
    border-radius: 16px;
    color: #fff;
    font-size: 14px;
    padding: 20px 24px;
    .title-wrap {
      display: flex;
      align-items: center;
      margin-bottom: 12px;
      .svg-icon {
        font-size: 24px;
        margin-right: 10px;
      }
    }
    .btn-wrap {
      display: flex;
      .btn {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 65px;
        height: 32px;
        border-radius: 8px;
        border: 1px solid #0560fd;
        margin-right: 8px;
        cursor: pointer;
        &.btn-delete {
          background-color: #0560fd;
        }
        &:last-child {
          margin-right: 0px;
        }
      }
    }
  }
}
</style>
